package xyz.zhzby.cyzx.oj.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import xyz.zhzby.cyzx.oj.constant.ProblemProcessEnum;
import xyz.zhzby.cyzx.oj.constant.ProblemStatusEnum;
import xyz.zhzby.cyzx.oj.constant.SubmissionTypeEnum;
import xyz.zhzby.cyzx.oj.convert.ProblemConvert;
import xyz.zhzby.cyzx.oj.dto.request.ProblemAddRequest;
import xyz.zhzby.cyzx.oj.dto.request.ProblemJudgeRequest;
import xyz.zhzby.cyzx.oj.dto.request.ProblemPageRequest;
import xyz.zhzby.cyzx.oj.dto.response.ProblemResponse;
import xyz.zhzby.cyzx.oj.entity.Problem;
import xyz.zhzby.cyzx.oj.mapper.ProblemMapper;
import xyz.zhzby.cyzx.oj.messenger.MessageSender;
import xyz.zhzby.cyzx.oj.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import xyz.zhzby.cyzx.security.entity.User;
import xyz.zhzby.cyzx.security.util.CyzxSecurityContextHolder;
import xyz.zhzby.cyzx.servicebase.domain.DataLogInfo;
import xyz.zhzby.cyzx.servicebase.domain.PageResponse;
import xyz.zhzby.cyzx.servicebase.domain.RestResponse;
import xyz.zhzby.cyzx.servicebase.exception.BusinessException;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 试题表 服务实现类
 * </p>
 *
 * @author zby
 * @since 2021-12-26
 */
@Service
public class ProblemServiceImpl extends ServiceImpl<ProblemMapper, Problem> implements IProblemService {

    @Autowired
    private IProblemCategoryService problemCategoryService;

    @Autowired
    private ICheckpointService checkpointService;

    @Autowired
    private ICategoryService categoryService;

    @Autowired
    private ISubmissionService submissionService;

    @Autowired
    private MessageSender messageSender;

    @Override
    public RestResponse<Long> createProblem(ProblemAddRequest problemAddRequest) {
        User subject = CyzxSecurityContextHolder.getSubject();
        problemAddRequest.setId(IdWorker.getId());

        problemCategoryService.linkProblemCategory(problemAddRequest.getId(), problemAddRequest.getCategoryIds());

        checkpointService.linkProblemCheckpoint(problemAddRequest.getId(), problemAddRequest.getCheckPoints());

        Problem problem = ProblemConvert.INSTANCE.REQUEST_PROBLEM(problemAddRequest);
        Integer count = baseMapper.selectCount(new LambdaQueryWrapper<>());
        problem.setNumber(count + 1);
        problem.setUserId(subject.getId());
        subject.fillCreateInfo(problem, DataLogInfo.USER_FIELD_ACTUAL_NAME);
        baseMapper.insert(problem);

        return RestResponse.success(problem.getId());
    }

    @Override
    public RestResponse<Long> updateProblem(ProblemAddRequest problemAddRequest) {
        User subject = CyzxSecurityContextHolder.getSubject();

        if (problemAddRequest.getStatus() == 1) {
            problemCategoryService.linkProblemCategory(problemAddRequest.getId(), problemAddRequest.getCategoryIds());
        }

        Problem problem = ProblemConvert.INSTANCE.REQUEST_PROBLEM(problemAddRequest);
        subject.fillUpdateInfo(problem, DataLogInfo.USER_FIELD_ACTUAL_NAME);
        baseMapper.updateById(problem);

        return RestResponse.success(problem.getId());
    }

    @Override
    public RestResponse<ProblemResponse> getProblemById(Long problemID) {
        Problem problem = baseMapper.selectById(problemID);
        if (problem == null) {
            return RestResponse.fail("试题不存在");
        }
        ProblemResponse response = ProblemConvert.INSTANCE.PROBLEM_RESPONSE(problem);
        response.setCategorys(categoryService.getLinkCategorysByProblemID(problemID));
        response.setCheckPoints(checkpointService.getLinkCheckpointsByProblemID(problemID));
        //todo 数据处理
        response.setLikeCount(666);
        response.setCollectCount(666);
        response.setCommentCount(666);
        response.setSubmitCount(888);
        response.setPassCount(666);
        return RestResponse.success(response);
    }

    @Override
    public RestResponse<PageResponse<ProblemResponse>> getProblemList(ProblemPageRequest problemPageRequest) {
        Page<Problem> page = new Page<>(problemPageRequest.getPage(), problemPageRequest.getLimit());
        LambdaQueryWrapper<Problem> qw = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(problemPageRequest.getSearch())) {
            // todo 万能搜索
        }
        if (problemPageRequest.getCategoryID() != null) {
            List<Long> problemIds = problemCategoryService.getProblemIdsByCategoryId(problemPageRequest.getCategoryID());
            problemIds.add(666L);
            qw.in(Problem::getId, problemIds);
        }
        if (problemPageRequest.getUserID() != null) {
            qw.eq(Problem::getUserId, problemPageRequest.getUserID());
        }
        if (problemPageRequest.getStatus() != null) {
            qw.eq(Problem::getStatus, problemPageRequest.getStatus());
        }
        if (problemPageRequest.getProcess() != null) {
            // todo 进程状态查询
        }
        qw.orderByAsc(Problem::getUpdateTime);
        IPage<Problem> pageData = baseMapper.selectPage(page, qw);
        List<Problem> records = pageData.getRecords();
        List<ProblemResponse> responses = ProblemConvert.INSTANCE.PROBLEM_RESPONSE_LIST(records);
        //todo 数据处理
        responses = responses.stream().map(pr -> {
            pr.setCommentCount(666);
            pr.setPassCount(666);
            pr.setSubmitCount(888);
            pr.setCollectCount(666);
            pr.setLikeCount(666);
            //todo  需要考虑未登录用户状态全为未开始
            pr.setProcess(ProblemProcessEnum.notBegin.getValue());
            return pr;
        }).collect(Collectors.toList());

        //todo 进程状态处理 上面137行

        return RestResponse.success(new PageResponse<>(responses, pageData.getTotal(), problemPageRequest.getPage(), problemPageRequest.getLimit()));
    }

    @Override
    public RestResponse<String> deleteProblem(Long problemID) {
        Problem problem = baseMapper.selectById(problemID);
        User subject = CyzxSecurityContextHolder.getSubject();
        if (problem.getStatus() == ProblemStatusEnum.recycle.getValue()) {
            baseMapper.deleteById(problemID);
            return RestResponse.success("删除成功");
        } else {
            problem.setStatus(ProblemStatusEnum.recycle.getValue());
            subject.fillUpdateInfo(problem, DataLogInfo.USER_FIELD_ACTUAL_NAME);
            baseMapper.updateById(problem);
            return RestResponse.success("已移至回收站");
        }
    }

    @Override
    public RestResponse<String> recycle(Long problemID) {
        Problem problem = new Problem();
        problem.setId(problemID);
        problem.setStatus(ProblemStatusEnum.draft.getValue());
        baseMapper.updateById(problem);
        return RestResponse.success("已恢复至草稿箱");
    }

    @Override
    public RestResponse<Long> getRandomProblem() {
        Problem problem = null;
        //防止出现意外查询不到
        while (problem == null) {
            LambdaQueryWrapper<Problem> qw = new LambdaQueryWrapper<>();
            Integer sum = baseMapper.selectCount(qw);
            int random = (int) (Math.random() * sum + 1);
            qw.eq(Problem::getNumber, random);
            problem = baseMapper.selectOne(qw);
        }
        return RestResponse.success(problem.getId());
    }

    @Override
    public RestResponse<String> testCode(ProblemJudgeRequest problemJudgeRequest) {
        Long submissionId = submissionService.createSubmission(problemJudgeRequest, SubmissionTypeEnum.test.getValue());

        Map<String, Object> mapMessage = new HashMap<>();
        mapMessage.put("event", "SubmissionCreated");
        mapMessage.put("submissionId", submissionId);
        messageSender.sendMessage(mapMessage);

        return RestResponse.success("提交成功，正在执行");
    }

    @Override
    public RestResponse<String> judgeCode(ProblemJudgeRequest problemJudgeRequest) {
        Long submissionId = submissionService.createSubmission(problemJudgeRequest, SubmissionTypeEnum.judge.getValue());

        Map<String, Object> mapMessage = new HashMap<>();
        mapMessage.put("event", "SubmissionCreated");
        mapMessage.put("submissionId", submissionId);
        messageSender.sendMessage(mapMessage);

        return RestResponse.success("提交成功，正在执行");
    }

}
